/*
 * bw_cgiutils.cpp
 *
 *  Created on: 2018年9月4日
 *  Author: Degang.Wu (windragon@126.com)
 *  Desc:
 */

#include "bw_public.h"
#include "bw_Str.h"
#include "../../common/cJSON.h"

#ifndef KEY_RET_CODE
#define KEY_RET_CODE	"retCode"
#endif
#ifndef KEY_RET_MSG
#define KEY_RET_MSG		"retMsg"
#endif

char g_outbuf[SZ_2M] = { 0 };

namespace bwcgi {

//ip地址字节序装换
unsigned int Addr_swap(unsigned int uiaddr)
{
	unsigned char pBuff[4] = {0};
	unsigned int ip = 0;

	pBuff[3] =(unsigned char)(uiaddr>>24);
    pBuff[2] =(unsigned char)(uiaddr>>16);
    pBuff[1] =(unsigned char)(uiaddr>>8);
    pBuff[0] =(unsigned char)(uiaddr);

	ip = (pBuff[0] << 24)|(pBuff[1] << 16)|(pBuff[2] << 8) |(pBuff[3]);

    return ip;
}

//ip装换为点分十进制字符串
char *iptostr(unsigned int ip)
{
	struct in_addr *in = NULL;
	in = (struct in_addr *)&ip;
	return  inet_ntoa(*in);
}

unsigned int ipstrtoint(char *val_str)
{

	std::string sip = val_str;
	bwcgi::BWStr::Array arr;
	bwcgi::BWStr::split_ex(arr, sip, ".");
	std::string dip;
	char tmp[128];
	if (arr.size() == 4)
	{
		snprintf(tmp, sizeof(tmp), "%d.%d.%d.%d",
				atoi(arr[0].c_str()), atoi(arr[1].c_str()), atoi(arr[2].c_str()), atoi(arr[3].c_str()));
		dip = tmp;
	}

	return inet_addr(dip.c_str());
}

int get_g_oubuf_size() {
	return sizeof(g_outbuf);
}

const char* bwenc_common_ack(eENC_ERROR code) {
	static std::string g_sResp;
	g_sResp.clear();
	st_ErrMsg* pErr = bwenc_get_errmsg(code);
	if (NULL == pErr) {
		pErr = bwenc_get_errmsg(BWENC_ERROR_UNKNOW);
	}
	cJSON* root = cJSON_CreateObject();

	cJSON_AddNumberToObject(root, KEY_RET_CODE, pErr->err_code);
	cJSON_AddStringToObject(root, KEY_RET_MSG, pErr->zh_msg);

	char *out = cJSON_PrintUnformatted(root);
	g_sResp = out;
	SAFE_FREE_PTR(out);
	cJSON_Delete(root);
//	cgi_debug("%s", g_sResp.c_str());

	return g_sResp.c_str();
}

class BwIOStream {
public:
	BwIOStream() :
			err(stderr) {
	}

	~BwIOStream() {

	}

	struct _IO_FILE* getStdErr() {
		return err;
	}
private:
	struct _IO_FILE* err;
};

static BwIOStream bwStdIO;

int FCGI_file_exist(const char *fname) {
	struct stat buf;
	return stat(fname, &buf) ? false : true;
}

void FCGI_file_split(PATH* rpath, const char* fullpath) {
	memset(rpath, 0, sizeof(PATH));
	snprintf(rpath->dir, sizeof(rpath->dir), "%s", fullpath);
	size_t i = 0;
	for (i = (strlen(rpath->dir) - 1); i > 0; i--) {
		if (rpath->dir[i] == '/' || rpath->dir[i] == '\\') {
			memcpy(rpath->file, &rpath->dir[i + 1], MAX_PATH - i - 1);
			memset(&rpath->dir[i], 0, MAX_PATH - i);
			break;
		}
	}

// mean just filename, have no dir
	if (strlen(rpath->file) == 0) {
		memset(rpath, 0, sizeof(PATH));
		snprintf(rpath->file, sizeof(rpath->file), "%s", fullpath);
	}
}

char* FCGI_module_name(void) {
	static char tmp[SZ_1K] = { 0 };
	if (strlen(tmp) < 1) {
		char szTmp[SZ_1K];
		snprintf(szTmp, sizeof(szTmp), "/proc/%d/exe", getpid());
		int bytes = bw_min(readlink(szTmp, tmp, SZ_1K), SZ_1K - 1);
		if (bytes >= 0) {
			tmp[bytes] = '\0';
		}
		PATH path;
		FCGI_file_split(&path, tmp);
		snprintf(tmp, sizeof(tmp), "%s", path.file);
	}
	return tmp;
}

char* FCGI_module_folder(void) {
	static char tmp[SZ_1K] = { 0 };
	if (strlen(tmp) < 1) {
		char szTmp[32];
		snprintf(szTmp, sizeof(szTmp), "/proc/%d/exe", getpid());
		int bytes = bw_min(readlink(szTmp, tmp, SZ_1K), SZ_1K - 1);
		if (bytes >= 0) {
			tmp[bytes] = '\0';
		}

		size_t len = strlen(tmp);
		size_t i = 0;
		for (i = len; i > 0; i--) {
			if (tmp[i] == '\\' || tmp[i] == '/') {
				memset(&tmp[i], 0, SZ_1K - i);
				break;
			}
		}
	}
	return tmp;
}

int FCGI_file_size(const char *fname) {
	struct stat buf;

	if (fname == NULL || stat(fname, &buf) < 0) {
		return -1;
	}
	return (int) buf.st_size;
}

/*
 * 日志先记录至内存盘(默认为："/var/log/ramfs"），到达条件再拷贝至flash
 */
int _FCGI_log(const char *format, ...) {
	va_list params;
	va_start(params, format);

	char _msg[SZ_2K];
	memset(_msg, 0, sizeof(_msg));
	vsnprintf(_msg, sizeof(_msg), format, params);

	std::string sMsg(_msg);
	BWStr::trim(sMsg);

	va_end(params);

	struct timeval tv = { 0 };
	gettimeofday(&tv, NULL);
	time_t _time = tv.tv_sec;
	struct tm occurs = { 0 };
	localtime_r(&_time, &occurs);

	char logFile[SZ_1K];
	snprintf(logFile, sizeof(logFile), "/var/log/%s.log", FCGI_module_name());

	char ramFile[SZ_1K];
	snprintf(ramFile, sizeof(ramFile), "%s/%s.log", BW_RAM_LOG_PATH,
			FCGI_module_name());

	if (FCGI_file_size(ramFile) > SZ_1M * 10) {
		char cmd[SZ_1K];
		snprintf(cmd, sizeof(cmd), "cp -f %s %s", ramFile, logFile);
		system(cmd);
		remove(ramFile);
	}

	FILE* fplog = fopen(ramFile, "a");
	if (fplog) {
		fprintf(fplog, "[%04d-%02d-%02d %02u:%02u:%02u.%03ld] %s\n",
				(1900 + occurs.tm_year), (1 + occurs.tm_mon), occurs.tm_mday,
				occurs.tm_hour, occurs.tm_min, occurs.tm_sec, tv.tv_usec / 1000,
				sMsg.c_str());
		fclose(fplog);
	}

	fprintf(bwStdIO.getStdErr(), "[%04d-%02d-%02d %02u:%02u:%02u.%03ld] %s\n",
			(1900 + occurs.tm_year), (1 + occurs.tm_mon), occurs.tm_mday,
			occurs.tm_hour, occurs.tm_min, occurs.tm_sec, tv.tv_usec / 1000,
			sMsg.c_str());

	return 0;
}

int FCGI_is_multicast(U32 ipaddr) {
	uint addressInNetworkOrder = htonl(ipaddr);
	return addressInNetworkOrder > 0xE00000FF
			&& addressInNetworkOrder <= 0xEFFFFFFF;
}

void FCGI_file_write(const char* fname, const char * buf, int buf_len) {
	if (!fname || !buf) {
		return;
	}

	FILE* fp = fopen(fname, "w");
	if (!fp) {
		return;
	}

	fwrite(buf, sizeof(U8), buf_len, fp);
	fclose(fp);
}

int FCGI_file_read(const char* fname, U8* buf, int buf_len) {
	if (!fname || !buf) {
		return -1;
	}

	FILE* fp = fopen(fname, "rb");
	if (!fp) {
		return -1;
	}
	fread(buf, sizeof(U8), buf_len, fp);
	fclose(fp);
	return 0;
}

int FCGI_shell_exec(const char* cmdline, char* out, size_t out_len) {
	FILE *pipe;
	char buf[1024] = { 0 };
	char result[64 * 1024];
	memset(result, 0, sizeof(result));
	char* p = result;
	if ((pipe = popen(cmdline, "r")) != NULL) {
		while (!feof(pipe) && !ferror(pipe)) {
			size_t n = fread(buf, 1, 1024, pipe);
			snprintf(p, sizeof(result) - strlen(result), "%s", buf);
			p += n;
		}
		pclose(pipe);
	}

	if (out) {
		snprintf(out, out_len, "%s", result);
	}
	return 0;
}

}  // namespace bwcgi
